babaiswikifandomcom-20200213-history
Advanced rulebook
Order of Operations A turn begins by calling command with key and player (for 2 player levels). *command calls: movecommand, MF_update *movecommand does movement logic (including doupdate calls) then does: doupdate, code, conversion, doupdate, code, moveblock *MF_update calls: code, miscblock, fallblock, doupdate, code, statusblock, conversion, fallblock, doupdate, code, levelblock, block, doupdate, code Descriptions of each of these functions: *`movecommand()`, before calling the other functions listed, executes all movement logic. Because it is complex, it will be described in its own section. *`conversion()` simultaneously converts all units to which conversion rules apply to. This is also where level conversions happen. Because it is simultaneous, you can convert an object into two different things, or e.g. 'baba on baba is rock' turns both babas into rocks. Because it runs two times after each move, 'key near empty is empty' will cause two rows of keys to become empty. However, each unit can only be converted once time per turn, and new units (either created or converted) are marked as converted this turn, so 'baba is keke is baba' only makes one change to a baba/keke per turn. *`moveblock()` applies the following properties and verbs in order: follow, back, tele, then all shift units force everything they could shift to face the appropriate direction. *`code()` is where, if the game thinks rules should be reparsed (updatecode 1), rules are reparsed until no further changes are detected (infinite loop at 200 times). Most things that could cause rules to have changed set updatecode to 1, like text being created/destroyed/moved, but there could be bugs related to word units not updating this correctly. *`doupdate()` is where the queue of outstanding changes is resolved (to allow for simultaneous movement and simultaneous conversions, for example). the kinds of updates are: update, updatedir, convert, emptyconvert, createall, dofloat. *`miscblock()` is where powered state is updated (depending on whether a unit with power property exists or not). *`fallblock()` is where falling units fall as far as possible. it repeats the process until nothing moves, so that solid fallers don't block each other in mid-air. unlike other kinds of movement, falling is immediate, not delayed until the next doupdate() call. *`statusblock()` updates units' float state, applies left/right/up/down properties to non-sleeping units, then updates some state used by back, hide, red and blue. *`levelblock()` applies properties and verbs to the level itself, in the order they rule is added to featureindex in (e.g. the order they're parsed in - this is a bug and hemi will probably fix it in the future): open/shut/win/defeat/weak/hot/melt/sink/tele/move/fall. *`block()` applies the following properties and verbs in order: done, blue, red, more, sink, weak, melt/hot, defeat, shut/open, eat, play, bonus, end, win, make, hide. Units are deleted after each property that could defeat them and will not be processed for later properties (this is e.g. why you can't win if you're defeated on the same turn). Movement logic Movement starts off with a series of 'takes'. Each take works identically, except that which units move in each take are different. *Take 1 consists of all non-sleeping you and you2 units. *Take 2 consists of all non-sleeping move, chill and fear effected units. *Take 3 consists of all shift effected units. After deciding what units are moving, repeat the following steps until nothing happens: #Iterate over moving units. For each unit, try to move it forward (including pull and push checks). If we succeed, generate a move for it and all push, pull, swap moves that would happen as a result. #For each unit that we generated a move for, move all those units simultaneously, including destroying units due to open/shut/weak/eat triggering on movement. If we moved anything, GOTO 1 (continue trying to move other units, since they might now be able to move). If we didn't, call `doupdate()` (to resolve those simultaneous movements - until this happens they haven't left their original tile!) and the take is over. (But before we do, flip units moving due to being 'move', effectively giving them a second chance to make their move.) (TODO: This is slightly more complicated especially in cases where move/shift is stacked.) Once the final take is done, we continue by calling the functions specified in the 'Order of operations' section. Named techniques Item Duplicating (Skull Housing) Normally when write A IS B, you create as many Bs as you used to have As. However, if you write A IS B and A IS C simultaneously in the same turn (or any similar construct like A IS B AND C), then you get both a B and a C for each A, doubling the amount of objects you had before. This process can usually be repeated to make arbitrarily many objects when it is possible. You don't even have to have a B and C - you can write A is B/A is B or A is B and B and you'll turn each A into two Bs. As long as you don't mind that they're stacked, this can be good enough too! Short on words, but can stack text? No problem - You can stack two A words on each other and write (A&A) is B, or stack two ISes and write A (is&is) B, or stack two Bs or a B and a C and write A is (B&B) or A is (B&C) to skull house. Vehicle (Crushers Trick) If you stack two SHIFT objects on the same tile, then they will move forward each turn. The reason this happens is because the two SHIFT objects queue SHIFT movements for each other simultaneously, then both movements are resolved. (Additionally, if they initially faced different directions, the first one in update order will make the second one face its direction before either one starts moving.) Prison Trick Normally if a rule is up against a wall and can only be moved along it, you can't ever break the rule. But if you could move the text onto an object, the object can move along the rule and break it apart from within. This is known as the Prison Trick because in the level Prison, you have to push WALL IS STOP onto an object that is YOU using a second object that is also YOU, letting you break it apart. Of course, this can also be done with any object that isn't solid that can then move or make something else move (using YOU, MOVE, SHIFT, etc). Text Stacking Normally since TEXT IS PUSH, TEXT is solid and no object can enter its tile. However there are many ways to get around this restriction, which work for different reasons: * TELE doesn't care if something solid is at its destination. Normally the objects on two TELEs will just exchange places, preventing stacking. But if one of the units has mismatching FLOAT with one of the TELEs or there are 3+ TELEs, you can have two different units land on the same TELE and stack them. * While TEXT can't move onto a tile containing TEXT, if two TEXTs simultaneously try to move onto the same tile, both moves succeed, leaving you with a stacked TEXT tile. This means they must happen in the same 'take' - that is, both moves must be caused by the same kind of initial movement (both YOU, both MOVE or both SHIFT). (Note that PUSH, PULL and SWAP are direct reactions to movement, and are considered to happen simultaneously with what triggered them, so two TEXT objects being SHIFTed onto the same tile is the same as if two MOVERs pushed two TEXT objects onto the same tile.) * TEXT can be created (by HAS or by conversion) on a tile that already has solid objects in it just fine. So if BABA HAS TEXT and BABA is destroyed while already on a TEXT tile, you will stack BABA and that TEXT object. * If you push a PUSH object onto a SWAP object, the pusher and SWAP object will overlap. Similarly, if you PULL an object while moving onto a SWAP object, the PULL and SWAP object will overlap. Object Unstacking If two objects are on the same tile and obey the same movement/solidity rules, it can be hard to separate them afterwards. Here are some things you can try: * While SINK will consume all objects simultaneously when it triggers, OPEN/SHUT being triggered as a reaction to movement will only consume one object. * Many rules related to tile-on-tile interactions (TELE, DEFEAT, HOT/MELT, SINK, OPEN/SHUT if the unit isn't in motion, WEAK) respect FLOAT. So if you can make one unit FLOAT and the other not, they can be separated this way. * If they're the same type of object but face in different directions, then a rule involving FACING or MOVE could get them to separate. * If they're different objects, making just one PUSH/PULL/YOU/MOVE/SHIFT/TELE will allow them to be separated. Update Order Shenanigans While no puzzle in vanilla Baba is You requires you to discover the update order between two units to solve it, some strange interactions happen if two simultaneous actions can't be resolved cleanly. Depending on which unit is processed first, different things will happen. Some examples: * If two SHIFT units try to act on each other, the earlier SHIFT unit will change everything else's direction to its before anything else happens. * If a unit tries to move to two different places simultaneously, it will move only to the second place - the movement will not be stacked, and any other consequences of the first movement will not be overridden either. For example, if two MOVE units try to push the same PUSH unit, then it will move in the direction of the second MOVE unit's push. If that PUSH propagated through to additional PUSH units in front of the first MOVE unit, even though the initial PUSH is overridden, the extra PUSHes still will, which creates a very 'non-physical' looking interaction: https://cdn.discordapp.com/attachments/556578457581256705/596769568672841738/2019-07-06_02-24-55.mp4 (Recorded by Silverhawke) * 'Time Travel Trick': If units are destroyed, then you undo their destruction, their relative update order may have changed. This means that doing and then undoing moves can be part of a puzzle's solution!